<template>
    <div id="containerId"></div>
</template>

<script setup>
import { onMounted } from "vue";
// 原理：基于 canvas 标签绘制像素点（位置，颜色等）在平面上计算出 3D 效果
// 下载并引入three库
import * as THREE from "three";
// 引入轨道控制器
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

let scene, camera, renderer, controls;
onMounted(() => {
    // 1.场景：放置物体的容器（世界）
    scene = new THREE.Scene();
    // 2.摄像机：类似于人眼，决定看到多大的空间范围
    camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
    // 3.渲染器：接收`场景`和`摄像机`，计算在浏览器上渲染的最终`2D画面`。
    renderer = new THREE.WebGLRenderer({antialias: true});
    // 3.1 将输出canvas的大小调整为(width, height)
    renderer.setSize( window.innerWidth, window.innerHeight );
    // 添加到页面中
    document.getElementById("containerId").appendChild( renderer.domElement );

    // 创建坐标轴，并添加场景世界中
    scene.add(createAxes(5))

    // 创建立方体
    let cube = createCubeColorFul({x: 3})
    // 创建坐标轴
    let axes = createAxes(3)
    // 将坐标轴添加到立方体中
    cube.add(axes)
    // 将立方体加入到场景世界中
    scene.add(cube); 
    // 旋转
    // cube.rotation.x = Math.PI/4;

    // 创建轨道控制器
    controls = createOrbit(camera, renderer.domElement)
    // 调用动画
    animate();

    // 移动摄像机
    camera.position.set( 2, 2, 8 )
    // 把 场景+摄像机 传递给渲染器进行渲染
    renderer.render(scene, camera)

    resize();
})

/**
 * 页面变化后重新绘制
*/
function resize() {
    window.addEventListener("resize", () => {
        // 设置画布（世界黑色背景）的宽高
        renderer.setSize(window.innerWidth, window.innerHeight);
        // 调整摄像机宽高比（防止被压缩）
        camera.aspect = window.innerWidth / window.innerHeight
        // 更新摄像机矩阵空间（让摄像机重新计算每个像素点位置和大小）
        camera.updateProjectionMatrix();
    })
}


/**
 * 添加动画效果
*/
function animate() {
    // 根据浏览器刷新帧率（默认1s 60次）不断递归调用此渲染函数，为了让render不断渲染最新的画面
    requestAnimationFrame( animate );
    // 轨道控制器属性改变，需要更新轨道控制器才有效果
    controls.update();
    renderer.render( scene, camera );
}

/**
 * 创建立方体
*/
function createCube({width=1, height=1, deep=1, x=0, y=0, z=0, color= 0x00ff00}={}) {
    // 1.几何图形 BoxGeometry 立方体（宽、高、深）1单位大小（three.js独有单位）
    const geometry = new THREE.BoxGeometry(width, height, deep);
    // 2.材质（皮肤）：决定我要一个什么样子的立方体（颜色）
    // MeshBasicMaterial 网格（面）基础（纯颜色）材质（0x 16进制颜色）
    const material = new THREE.MeshBasicMaterial({ color: color });
    // 3.创建物体（Mesh）网格材质（面）
    const cube = new THREE.Mesh(geometry, material);
    cube.position.x = x;
    cube.position.y = y;
    cube.position.z = z;
    return cube;
}


/**
 * 创建五颜六色立方体
*/
function createCubeColorFul({width=1, height=1, deep=1,x=0, y=0, z=0,colorArr= ["red", "green", "blue", "pink", "orange", "white"]}={}) {
    // 1.几何图形 BoxGeometry 立方体（宽、高、深）1单位大小（three.js独有单位）
    const geometry = new THREE.BoxGeometry(width, height, deep);
    // 2.材质（皮肤）：决定我要一个什么样子的立方体（颜色）
    let materialArr = colorArr.map(item => {
        // MeshBasicMaterial 网格（面）基础（纯颜色）材质（0x 16进制颜色）
        return new THREE.MeshBasicMaterial({ color: item });
    })
    // 3.创建物体（Mesh）网格材质（面）
    const cube = new THREE.Mesh(geometry, materialArr);
    cube.position.x = x;
    cube.position.y = y;
    cube.position.z = z;
    return cube;
}


/**
 * 创建坐标轴
*/
function createAxes(size=1) {
    const axesHelper = new THREE.AxesHelper( size );
    return axesHelper
}


/**
 * 创建轨道控制器
*/
function createOrbit (camera, domElement) {
    const controls = new OrbitControls( camera, domElement )
    controls.update();
    return controls
}
</script>